package no.ntnu.fp.services.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import no.ntnu.fp.messages.impl.MeetingDeletedMessage;
import no.ntnu.fp.messages.impl.MeetingUpdatedMessage;
import no.ntnu.fp.messages.impl.NoticeAddedOrUpdatedMessage;
import no.ntnu.fp.model.Employee;
import no.ntnu.fp.model.Meeting;
import no.ntnu.fp.model.Notice;
import no.ntnu.fp.model.Notice.NoticeType;
import no.ntnu.fp.net.co.Connection;
import no.ntnu.fp.server.MainConnection;
import no.ntnu.fp.services.NoticeService;
import no.ntnu.fp.storage.MeetingStorage;
import no.ntnu.fp.storage.NoticeStorage;
import no.ntnu.fp.utils.Participant;

public class NoticeServiceImpl extends EntityServiceImpl<Notice> implements NoticeService {
	private final NoticeStorage noticeStorage;
	private final MeetingStorage meetingStorage;

	public NoticeServiceImpl(NoticeStorage noticeStorage,
			MeetingStorage meetingStorage) {
		this.noticeStorage = noticeStorage;
		this.meetingStorage = meetingStorage;
	}

	public List<Notice> getUnreadNoticesByEmployee(Employee employee) {
		return noticeStorage.getUnreadNoticesByEmployee(employee);
	}

	@Override
	public Notice markAsRead(Notice notice) {
		return noticeStorage.markAsRead(notice);
	}

	@Override
	public Notice addNotice(Notice notice) {
		return noticeStorage.addNotice(notice);
	}

	@Override
	public void notifyParticipants(Meeting meeting, NoticeType type, 
			Employee notifier) {
		List<Participant> meetingParticipants = meeting.getParticipants();
		List<Participant> participants = new ArrayList<Participant>();
		participants.add(new Participant(meeting.getEmployee(), true));
		if (meetingParticipants != null) {
			participants.addAll(meetingParticipants);
		}
		notifyParticipants(meeting, type, notifier, participants);
	}

	private void notifyParticipants(Meeting meeting, NoticeType type,
			Employee notifier, List<Participant> participants) {
		for (Participant p: participants) {
			if (!p.getEmployee().equals(notifier)) {
				Employee employee = p.getEmployee();
				Notice notice = new Notice(-1, employee, meeting, type, "",
						false);
				notice = addNotice(notice);
				NoticeAddedOrUpdatedMessage noticeMessage 
				= new NoticeAddedOrUpdatedMessage(notice, notifier);
				Connection connection = MainConnection.getConnection(employee);
				if (connection != null) {
					try {
						if(type == NoticeType.ParticipantAccepted
								|| type == NoticeType.ParticipantDeclined){
							MeetingUpdatedMessage updatedMeeting = 
								new MeetingUpdatedMessage(meeting);
							connection.send(updatedMeeting.toString());
						}else if(type == NoticeType.ChangedMeeting){
							MeetingDeletedMessage deletedMessage = 
								new MeetingDeletedMessage(meeting);
							connection.send(deletedMessage.toString());
						}
						connection.send(noticeMessage.toString());
						if(type == NoticeType.CancelledMeeting){
							connection.send(
									new MeetingDeletedMessage(meeting).toString());
						}
					} catch (IOException ex) {
						System.err.printf(
								"Could not send notice %s to employee %s",
								notice, employee);
						ex.printStackTrace();
					}
				}
			}
		}
	}

	@Override
	public Meeting acceptNotice(Notice notice) {
		Meeting meeting = notice.getMeeting();
		Employee participant = notice.getEmployee();
		meeting = meetingStorage.markAsParticipating(meeting, participant);
		//Notify meeting.getEmployee() ogs� - m�teinnkaller
		if(!meeting.isCancelled()){
			notifyParticipants(meeting, NoticeType.ParticipantAccepted, participant);
		}
		return meeting;
	}
	@Override
	public void rejectNotice(Notice notice) {
		Meeting meeting = notice.getMeeting();
		Employee participant = notice.getEmployee();
		meeting = meetingStorage.markNotParticipating(meeting, participant);
		notifyParticipants(meeting, NoticeType.ParticipantDeclined, participant);
	}

	@Override
	public void sendDeletionNotice(List<Participant> oldParticipants,
			Meeting meeting) {
		notifyParticipants(meeting, NoticeType.CancelledMeeting, 
				meeting.getEmployee(), oldParticipants);

	}
}